package cn.tedu.imop.gateway.config;

import com.alibaba.cloud.sentinel.SentinelProperties;
import com.alibaba.cloud.sentinel.datasource.RuleType;
import com.alibaba.cloud.sentinel.datasource.config.DataSourcePropertiesConfiguration;
import com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties;
import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;

import java.util.List;

public class SentinelNacosDataSourceHandler implements SmartInitializingSingleton {

    private static final Logger logger = LoggerFactory.getLogger(SentinelNacosDataSourceHandler.class);

    private final SentinelProperties sentinelProperties;

    public SentinelNacosDataSourceHandler(SentinelProperties sentinelProperties) {
        this.sentinelProperties = sentinelProperties;
    }

    @Override
    public void afterSingletonsInstantiated() {
        sentinelProperties.getDatasource().values().forEach(this::registryWriter);
    }

    private void registryWriter(DataSourcePropertiesConfiguration dataSourceProperties) {
        System.out.println("dataSourceProperties="+dataSourceProperties);
        final NacosDataSourceProperties nacosDataSourceProperties = dataSourceProperties.getNacos();
        if (nacosDataSourceProperties == null) {
            logger.warn("NacosDataSourceProperties is null, skipping registration.");
            return;
        }
        final RuleType ruleType = nacosDataSourceProperties.getRuleType();
        logger.info("Registering writer for rule type: {}", ruleType);

        // 通过数据源配置的 ruleType 来注册数据源
        switch (ruleType) {
            case GW_FLOW:
                registerDataSource(nacosDataSourceProperties, JSON::toJSONString, WritableDataSourceRegistry::registerFlowDataSource);
                break;
            case DEGRADE:
                registerDataSource(nacosDataSourceProperties, JSON::toJSONString, WritableDataSourceRegistry::registerDegradeDataSource);
                break;
            case PARAM_FLOW:
                WritableDataSource<List<ParamFlowRule>> paramFlowRuleWriter = new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString);
                ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWriter);
                break;
            case SYSTEM:
                registerDataSource(nacosDataSourceProperties, JSON::toJSONString, WritableDataSourceRegistry::registerSystemDataSource);
                break;
            case AUTHORITY:
                registerDataSource(nacosDataSourceProperties, JSON::toJSONString, WritableDataSourceRegistry::registerAuthorityDataSource);
                break;
            default:
                logger.warn("Unsupported rule type: {}", ruleType);
                break;
        }
    }

    private <T> void registerDataSource(NacosDataSourceProperties nacosDataSourceProperties, Converter<T, String> converter, DataSourceRegistrar<T> registrar) {
        try {
            WritableDataSource<T> dataSource = new NacosWritableDataSource<>(nacosDataSourceProperties, converter);
            registrar.register(dataSource);
            logger.info("Registered writable data source for rule type: {}", nacosDataSourceProperties.getRuleType());
        } catch (Exception e) {
            logger.error("Failed to register writable data source for rule type: {}", nacosDataSourceProperties.getRuleType(), e);
        }
    }
    @FunctionalInterface
    interface DataSourceRegistrar<T> {
        void register(WritableDataSource<T> dataSource);
    }
}